package com.github.nukc.stateview;

import com.github.nukc.stateview.view.MaterialRippleLayout;
import com.github.nukc.stateview.view.ProgressWheel;

import ohos.aafwk.ability.Ability;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentParent;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.ListContainer;
import ohos.agp.components.NestedScrollCoordinator;
import ohos.agp.components.NestedScrollView;
import ohos.agp.components.ScrollView;
import ohos.agp.components.StackLayout;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.window.service.DisplayAttributes;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.NoSuchElementException;

/**
 * StateView
 *
 * @since 2021-04-26
 */
public class StateView extends ComponentContainer {
    /**
     * EMPTY值
     */
    public static final int EMPTY = 0x00000000;
    /**
     * RETRY值
     */
    public static final int RETRY = 0x00000001;
    /**
     * LOADING值
     */
    public static final int LOADING = 0x00000002;
    static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00206, "StateView");

    /**
     * 点击类型
     *
     * @since 2021-03-01
     */
    public enum ShowType {
        /**
         * 重新点击
         */
        RETRY,
        /**
         * 内容为空
         */
        EMPTY,
        /**
         * 加载中
         */
        LOADING
    }

    /**
     * ViewType
     *
     * @since 2021-04-26
     */
    @IntDef({EMPTY, RETRY, LOADING})
    @Retention(RetentionPolicy.SOURCE)
    public @interface ViewType {
    }

    private static final float RIPPLE_ALPHA = 0.2f;
    private static final int RIPPLE_DURATION = 2000;
    private static final int RIPPLE_DIAMETERDP = 20;
    private static final int BARLENGTH = 260;
    private static final int BARWIDTH = 10;
    private static final int RIMWIDTH = 10;
    private static final int SPINSPEED = 20;
    private static int injectScreenHeight = 0;
    private static ComponentContainer injectComponent;
    private int mEmptyResource;
    private int mRetryResource;
    private int mLoadingResource;

    private Component mEmptyView;
    private Component mRetryView;
    private Component mLoadingView;
    private EventHandler eventHandler;

    private LayoutScatter mInflater;
    private OnRetryClickListener mRetryClickListener;
    private OnInflateListener mInflateListener;

    private DependentLayout.LayoutConfig mLayoutParamsRelative;
    private DependentLayout.LayoutConfig mLayoutParamsConstrain;
    private AnimatorProvider mProvider = null;
    private boolean isConstraintLayout = false;
    private int constraintMarginBottom;
    private int constraintMarginTop;
    private int constraintWidth;
    private int constraintHeight;
    private boolean isRelative = false;
    private int relativeWidth;
    private int relativeHeight;
    private int relativeMarginTop;
    private boolean isEmptyView = false;
    private boolean isInject = false;
    private boolean isAnimator = false;
    private boolean isDrawerLayout = false;
    private int drawerLayoutMarginBottom;
    private boolean isWrap = false;
    private boolean isInjectRv = false;
    private String defaultColor = "#FFFFFFFF";
    private String darkGreyColor = "#2E2E2E";

    /**
     * 构造器
     *
     * @param context 上下文
     */
    public StateView(Context context) {
        this(context, null);
    }

    /**
     * 构造器
     *
     * @param context 上下文
     * @param attrs   属性集合
     */
    public StateView(Context context, AttrSet attrs) {
        this(context, attrs, "");
    }

    /**
     * 构造器
     *
     * @param context   上下文
     * @param attrs     属性集合
     * @param styleName 类型名称
     */
    public StateView(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
        if (null != attrs) {
            if (attrs.getAttr("emptyResource").isPresent()) {
                mEmptyResource = attrs.getAttr("emptyResource").get().getIntegerValue();
            }

            if (attrs.getAttr("retryResource").isPresent()) {
                mRetryResource = attrs.getAttr("retryResource").get().getIntegerValue();
            }

            if (attrs.getAttr("loadingResource").isPresent()) {
                mLoadingResource = attrs.getAttr("loadingResource").get().getIntegerValue();
            }
        }

        if (mEmptyResource == 0) {
            mEmptyResource = ResourceTable.Layout_base_empty;
        }
        if (mRetryResource == 0) {
            mRetryResource = ResourceTable.Layout_base_retry;
        }
        if (mLoadingResource == 0) {
            mLoadingResource = ResourceTable.Layout_base_loading;
        }

        if (attrs == null) {
            mLayoutParamsRelative = new DependentLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
                    ComponentContainer.LayoutConfig.MATCH_PARENT);
            mLayoutParamsConstrain = new DependentLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
                    ComponentContainer.LayoutConfig.MATCH_PARENT);
        } else {
            mLayoutParamsRelative = new DependentLayout.LayoutConfig(context, attrs);
            mLayoutParamsConstrain = new DependentLayout.LayoutConfig(context, attrs);
        }

        setVisibility(HIDE);
    }

    public boolean isConstraintLayout() {
        return isConstraintLayout;
    }

    public void setConstraintLayout(boolean constraintLayout) {
        isConstraintLayout = constraintLayout;
    }

    /**
     * 设置Constraint的下边距和上边距
     *
     * @param marginBottom 下边距
     * @param marginTop    上边距
     */
    public void setConstraintMarginBottomAndTop(int marginBottom, int marginTop) {
        this.constraintMarginBottom = marginBottom;
        this.constraintMarginTop = marginTop;
    }

    /**
     * 设置Constraint宽度和高度
     *
     * @param width  宽度
     * @param height 高度
     */
    public void setConstraintWidthAndHeight(int width, int height) {
        this.constraintWidth = width;
        this.constraintHeight = height;
    }


    public boolean isRelative() {
        return isRelative;
    }

    public void setRelative(boolean relative) {
        isRelative = relative;
    }

    /**
     * 设置Relative宽度和高度
     *
     * @param width  宽度
     * @param height 高度
     */
    public void setRelativeWidthAndHeight(int width, int height) {
        relativeWidth = width;
        relativeHeight = height;
    }

    public void setRelativeMarginTop(int top) {
        relativeMarginTop = top;
    }

    public boolean isInject() {
        return isInject;
    }

    public void setInject(boolean inject) {
        isInject = inject;
    }

    public boolean isEmptyView() {
        return isEmptyView;
    }

    public void setEmptyView(boolean emptyView) {
        isEmptyView = emptyView;
    }

    public boolean isAnimator() {
        return isAnimator;
    }

    public void setAnimator(boolean animator) {
        isAnimator = animator;
    }

    public boolean isDrawerLayout() {
        return isDrawerLayout;
    }

    public void setDrawerLayout(boolean drawerLayout) {
        isDrawerLayout = drawerLayout;
    }

    public int getDrawerLayoutMarginBottom() {
        return drawerLayoutMarginBottom;
    }

    public void setDrawerLayoutMarginBottom(int drawerLayoutMarginBottom) {
        this.drawerLayoutMarginBottom = drawerLayoutMarginBottom;
    }

    public boolean isWrap() {
        return isWrap;
    }

    public void setWrap(boolean wrap) {
        isWrap = wrap;
    }

    public void setInjectRv(boolean injectRv) {
        isInjectRv = injectRv;
    }


    /**
     * 注入到 ability 中
     *
     * @param ability Ability
     * @return StateView
     */
    public static StateView inject(@NonNull Ability ability) {
        return inject(ability, false);
    }

    /**
     * 注入到 ability 中
     *
     * @param ability Ability
     * @param hasActionBar 是否有 actionbar/toolbar
     * @return StateView
     */
    public static StateView inject(@NonNull Ability ability, boolean hasActionBar) {
        ComponentContainer rootView = (ComponentContainer) ability.getWindow().getCurrentComponentFocus().
                get().findComponentById(ResourceTable.Id_content);
        return inject(rootView, hasActionBar);
    }

    /**
     * 注入到 ViewGroup 中
     *
     * @param parent extends ViewGroup
     * @return StateView
     */
    public static StateView inject(@NonNull ComponentContainer parent) {
        return inject(parent, false);
    }

    /**
     * 注入到 ViewGroup 中
     *
     * @param parent       extends ViewGroup
     * @param hasActionBar 是否有 actionbar/toolbar
     * @return StateView
     * @throws IllegalStateException 异常
     */
    public static StateView inject(@NonNull ComponentContainer parent, boolean hasActionBar) {
        injectComponent = parent;

        // 因为 LinearLayout/ScrollView/AdapterView 的特性
        // 为了 StateView 能正常显示，自动再套一层（开发的时候就不用额外的工作量了）
        judeComponent();
        StateView stateView = new StateView(injectComponent.getContext());
        if (injectScreenHeight > 0) {
            // let StateView be shown in the center
            ComponentContainer.LayoutConfig params = new ComponentContainer.LayoutConfig(
                    ComponentContainer.LayoutConfig.MATCH_PARENT,
                    hasActionBar ? injectScreenHeight - stateView.getActionBarHeight() : injectScreenHeight);
            injectComponent.addComponent(stateView, params);
        } else {
            injectComponent.addComponent(stateView);
        }
        if (hasActionBar) {
            stateView.setTopMargin();
        }
        stateView.getLayoutConfig().width = ComponentContainer.LayoutConfig.MATCH_PARENT;
        stateView.getLayoutConfig().height = ComponentContainer.LayoutConfig.MATCH_PARENT;
        return stateView;
    }

    /**
     * 注入到 View 中
     *
     * @param view instanceof ViewGroup
     * @return StateView
     */
    public static StateView inject(@NonNull Component view) {
        return inject(view, false);
    }

    /**
     * 注入到 View 中
     *
     * @param view         instanceof ViewGroup
     * @param hasActionBar 是否有 actionbar/toolbar
     * @return StateView 返回StateView实例对象
     * @throws ClassCastException 类型转换异常
     */
    public static StateView inject(@NonNull Component view, boolean hasActionBar) {
        if (view instanceof ComponentContainer) {
            ComponentContainer parent = (ComponentContainer) view;
            return inject(parent, hasActionBar);
        } else {
            ComponentParent parent = view.getComponentParent();
            if (parent instanceof ComponentContainer) {
                return inject((ComponentContainer) parent, hasActionBar);
            } else {
                throw new ClassCastException("view or view.getParent() must be ViewGroup");
            }
        }
    }


    private static void judeComponent() {
        if (!judgeCondition()) {
            return;
        }
        ComponentParent viewParent = injectComponent.getComponentParent();
        if (viewParent == null) {
            StackLayout wrapper = new StackLayout(injectComponent.getContext());
            ComponentContainer.LayoutConfig layoutParams = new ComponentContainer.LayoutConfig(
                    ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
            wrapper.setLayoutConfig(layoutParams);
            if (injectComponent instanceof DirectionalLayout) {
                DirectionalLayout wrapLayout = new DirectionalLayout(injectComponent.getContext());
                wrapLayout.setLayoutConfig(injectComponent.getLayoutConfig());
                wrapLayout.setOrientation(((DirectionalLayout) injectComponent).getOrientation());
                for (int index = 0, childCount = injectComponent.getChildCount(); index < childCount; index++) {
                    Component childView = injectComponent.getComponentAt(0);
                    injectComponent.removeComponent(childView);
                    wrapLayout.addComponent(childView);
                }
                wrapper.addComponent(wrapLayout);
            } else if (injectComponent instanceof ScrollView) {
                if (injectComponent.getChildCount() != 1) {
                    throw new IllegalStateException("the ScrollView does not have one direct child");
                }
                Component directView = injectComponent.getComponentAt(0);
                injectComponent.removeComponent(directView);
                wrapper.addComponent(directView);
                DisplayAttributes diplay = DisplayManager.getInstance().getDefaultDisplay(injectComponent.
                        getContext()).get().getAttributes();
                injectScreenHeight = diplay.height;
            } else if (injectComponent instanceof NestedScrollCoordinator
                    && injectComponent instanceof NestedScrollView) {
                final int childNum = 2;
                if (injectComponent.getChildCount() == childNum) {
                    Component targetView = injectComponent.getComponentAt(1);
                    injectComponent.removeComponent(targetView);
                    wrapper.addComponent(targetView);
                } else if (injectComponent.getChildCount() > childNum) {
                    throw new IllegalStateException(injectComponent.toString() + "is not refresh layout?");
                }
            } else {
                throw new IllegalStateException(injectComponent.toString() + "does not have parent");
            }
            injectComponent.addComponent(wrapper);
            injectComponent = wrapper;
        } else {
            viewParentIsNotNull(viewParent);
        }
    }

    private static boolean judgeCondition() {
        boolean judgeCondition = injectComponent instanceof DirectionalLayout || injectComponent instanceof ScrollView
                || (injectComponent instanceof ScrollView && injectComponent instanceof NestedScrollView);
        boolean judgeCondition2 = (injectComponent instanceof NestedScrollCoordinator
                && injectComponent instanceof NestedScrollView) || injectComponent instanceof ListContainer;
        return judgeCondition || judgeCondition2;
    }


    private static void viewParentIsNotNull(ComponentParent viewParent) {
        StackLayout root = new StackLayout(injectComponent.getContext());
        root.setLayoutConfig(injectComponent.getLayoutConfig());

        if (viewParent instanceof ComponentContainer) {
            ComponentContainer rootGroup = (ComponentContainer) viewParent;
            rootGroup.removeComponent(injectComponent);
            rootGroup.addComponent(root);
            Injector.changeChildrenConstraints(rootGroup, root, injectComponent.getId());
        }
        ComponentContainer.LayoutConfig layoutParams = new ComponentContainer.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        injectComponent.setLayoutConfig(layoutParams);
        root.addComponent(injectComponent);
        injectComponent = root;
    }

    /**
     * 包裹 view
     *
     * @param view target view
     * @return StateView
     */
    public static StateView wrap(@NonNull Component view) {
        ComponentContainer parent = (ComponentContainer) view.getComponentParent();
        parent.removeComponent(view);
        StackLayout wrap = new StackLayout(view.getContext());
        wrap.addComponent(view);
        StateView stateView = new StateView(view.getContext());
        wrap.addComponent(stateView, view.getLayoutConfig());
        parent.addComponent(wrap);
        return stateView;
    }

    @Override
    public void setVisibility(int visibility) {
        setVisibility(mEmptyView, visibility);
        setVisibility(mRetryView, visibility);
        setVisibility(mLoadingView, visibility);
    }

    private void setVisibility(Component view, int visibility) {
        if (view != null && visibility != view.getVisibility()) {
            if (mProvider != null) {
                startAnimation(view);
            } else {
                view.setVisibility(visibility);
            }
        }
    }

    /**
     * 展示原始内容
     */
    public void showContent() {
        setVisibility(HIDE);
    }

    /**
     * 展示空内容页面
     *
     * @return Component 组件
     */
    public Component showEmpty() {
        if (mEmptyView == null) {
            mEmptyView = inflate(mEmptyResource, EMPTY);
        }
        setStyleByViewType(mEmptyView, ShowType.EMPTY);
        showView(mEmptyView);
        return mEmptyView;
    }

    /**
     * 展示重试内容页面
     *
     * @return Component 组件
     */
    public Component showRetry() {
        try {
            if (mRetryView == null) {
                mRetryView = inflate(mRetryResource, RETRY);
                mRetryView.setClickedListener(new ClickedListener() {
                    static final int delayTime = 600;

                    @Override
                    public void onClick(Component component) {
                        if (mRetryClickListener != null) {
                            showLoading();
                            if (eventHandler == null) {
                                eventHandler = new EventHandler(EventRunner.getMainEventRunner());
                            }
                            eventHandler.postTask(new Runnable() {
                                @Override
                                public void run() {
                                    mRetryClickListener.onRetryClick();
                                }
                            }, delayTime);
                        }
                    }
                });
            }
        } catch (NoSuchElementException e) {
            HiLog.info(LABEL, "Exception = " + e.toString());
        }
        setStyleByViewType(mRetryView, ShowType.RETRY);
        showView(mRetryView);
        return mRetryView;
    }

    /**
     * 展示加载内容页面
     *
     * @return Component 组件
     */
    public Component showLoading() {
        if (mLoadingView == null) {
            mLoadingView = inflate(mLoadingResource, LOADING);

        }
        setStyleByViewType(mLoadingView, ShowType.LOADING);
        showView(mLoadingView);
        return mLoadingView;
    }

    /**
     * 展示动画效果
     *
     * @param target 绑定组件
     * @param color  颜色
     */
    public void showAnimator(Component target, String color) {
        Button loading = (Button) target.findComponentById(ResourceTable.Id_loading);
        if (null == loading) {
            return;
        }
        startAnimator(loading);
        ProgressWheel pwOne = (ProgressWheel) target.findComponentById(ResourceTable.Id_pw);
        pwOne.setBarColor(Color.getIntColor("#FF3E96"));
        pwOne.setRimColor(Color.getIntColor(color));
        pwOne.setBarLength(BARLENGTH);
        pwOne.setBarWidth(BARWIDTH);
        pwOne.setRimWidth(RIMWIDTH);
        pwOne.setSpinSpeed(SPINSPEED);

        // 启动动画旋转
        pwOne.startSpinning();
    }

    /**
     * 按视图类型设置组件样式
     *
     * @param target 组件
     * @param type   视图类型
     */
    public void setStyleByViewType(Component target, ShowType type) {
        if (null != target) {
            judgeAbility(target);
            judgeAbility2(target, type);
            judgeAbility3(target, type);
        }
    }

    private void judgeAbility3(Component target, ShowType type) {
        if (isAnimator) {
            target.setMarginTop(0);
            if (ShowType.LOADING == type) {
                ShapeElement background = new ShapeElement();
                background.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#F5F5F5")));
                target.setBackground(background);
            }
        }
        if (isDrawerLayout) {
            target.setMarginBottom(drawerLayoutMarginBottom);
        }
        if (isWrap && ShowType.RETRY == type) {
            Component textComponent = target.findComponentById(ResourceTable.Id_edit);
            if (textComponent instanceof Text ) {
                ((Text) textComponent).setText("Something");
            }
            Component textComponent2 = target.findComponentById(ResourceTable.Id_edit2);
            if (textComponent2 instanceof Text ) {
                ((Text) textComponent2).setText("went wrong!");
            }
            Component textComponent3 = target.findComponentById(ResourceTable.Id_edit3);
            if (textComponent3 instanceof Text ) {
                textComponent3.setVisibility(VISIBLE);
            }
        }
        if (isEmptyView) {
            if (ShowType.LOADING == type) {
                ShapeElement background = new ShapeElement();
                background.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor(darkGreyColor)));
                target.setBackground(background);

            }
            if (ShowType.RETRY == type) {
                Component textComponent1 = target.findComponentById(ResourceTable.Id_edit);
                Component textComponent2 = target.findComponentById(ResourceTable.Id_edit2);
                if (textComponent1 instanceof Text ) {
                    ((Text) textComponent1).setText("Content");
                }
                if (textComponent2 instanceof Text ) {
                    ((Text) textComponent2).setVisibility(HIDE);
                }

            }
        }
    }

    private void judgeAbility2(Component target, ShowType type) {
        if (isInject) {
            if (ShowType.RETRY == type) {
                ShapeElement background = new ShapeElement();
                background.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor(darkGreyColor)));
                target.setBackground(background);
                Component textComponent = target.findComponentById(ResourceTable.Id_edit);
                if (textComponent instanceof Text ) {
                    ((Text) textComponent).setTextColor(new Color(Color.getIntColor(defaultColor)));
                }
                Component textComponent2 = target.findComponentById(ResourceTable.Id_edit2);
                if (textComponent2 instanceof Text ) {
                    ((Text) textComponent2).setTextColor(new Color(Color.getIntColor(defaultColor)));
                }
            }
            if (ShowType.EMPTY == type) {
                ShapeElement background = new ShapeElement();
                background.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor(darkGreyColor)));
                target.setBackground(background);
                Component textComponent = target.findComponentById(ResourceTable.Id_edit);
                if (textComponent instanceof Text ) {
                    ((Text) textComponent).setTextColor(new Color(Color.getIntColor(defaultColor)));
                }
            }
            if (ShowType.LOADING == type) {
                ShapeElement background = new ShapeElement();
                background.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor(darkGreyColor)));
                target.setBackground(background);

                Component textComponent1 = target.findComponentById(ResourceTable.Id_edit);
                Component textComponent3 = target.findComponentById(ResourceTable.Id_edit2);
                if (textComponent1 instanceof Text ) {
                    ((Text) textComponent1).setVisibility(HIDE);
                }
                if (textComponent3 instanceof Text ) {
                    ((Text) textComponent3).setVisibility(HIDE);
                }
            }
        }
    }

    private void judgeAbility(Component target) {
        if (isInject || isEmptyView) {
            showAnimator(target, darkGreyColor);
        } else {
            showAnimator(target, "#fffeee");
        }

        if (isConstraintLayout) {
            target.setMarginBottom(constraintMarginBottom);
            target.setMarginTop(constraintMarginTop);
            target.setHeight(constraintHeight);
            target.setWidth(constraintWidth);
        }
        if (isRelative) {
            target.setWidth(relativeWidth);
            target.setHeight(relativeHeight);
            target.setMarginTop(relativeMarginTop);
            ShapeElement background = new ShapeElement();
            background.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#FAFAFA")));
            target.setBackground(background);
        }
        if (isInjectRv) {
            target.setMarginTop(0);
        }
    }

    /**
     * show the state view
     *
     * @param view view
     */
    private void showView(Component view) {
        setVisibility(view, VISIBLE);
        hideViews(view);
    }

    private void startAnimator(Button bt) {
        if (bt == null) {
            return;
        }
    }

    /**
     * hide other views after show view
     *
     * @param showView showView
     */
    private void hideViews(Component showView) {
        if (mEmptyView == showView) {
            setVisibility(mLoadingView, HIDE);
            setVisibility(mRetryView, HIDE);
        } else if (mLoadingView == showView) {
            setVisibility(mEmptyView, HIDE);
            setVisibility(mRetryView, HIDE);
        } else {
            setVisibility(mEmptyView, HIDE);
            setVisibility(mLoadingView, HIDE);
        }
    }

    private void startAnimation(final Component view) {
        final boolean toShow = view.getVisibility() == HIDE;
        Animator theAnimator = toShow ? mProvider.showAnimation(view) : mProvider.hideAnimation(view);
        if (theAnimator instanceof AnimatorProperty) {
            AnimatorProperty animator2 = (AnimatorProperty) theAnimator;
            setAnimatorProperty(animator2, view, toShow);
            animator2.start();
        } else {
            AnimatorGroup animator2 = (AnimatorGroup) theAnimator;
            if (animator2 == null) {
                view.setVisibility(toShow ? VISIBLE : HIDE);
                return;
            }
            animator2.setStateChangedListener(new Animator.StateChangedListener() {
                @Override
                public void onStart(Animator newAnimator) {
                    if (toShow) {
                        view.setVisibility(VISIBLE);
                    }
                }

                @Override
                public void onStop(Animator newAnimator) {

                }

                @Override
                public void onCancel(Animator newAnimator) {

                }

                @Override
                public void onEnd(Animator newAnimator) {
                    if (!toShow) {
                        view.setVisibility(HIDE);
                    }
                }

                @Override
                public void onPause(Animator newAnimator) {

                }

                @Override
                public void onResume(Animator newAnimator) {

                }
            });
            animator2.start();
        }
    }

    private void setAnimatorProperty(AnimatorProperty animator2, Component view, boolean toShow) {
        if (animator2 == null) {
            view.setVisibility(toShow ? VISIBLE : HIDE);
            return;
        }
        animator2.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator newAnimator) {
                if (toShow) {
                    view.setVisibility(VISIBLE);
                }
            }

            @Override
            public void onStop(Animator newAnimator) {

            }

            @Override
            public void onCancel(Animator newAnimator) {

            }

            @Override
            public void onEnd(Animator newAnimator) {
                if (!toShow) {
                    view.setVisibility(HIDE);
                }
            }

            @Override
            public void onPause(Animator newAnimator) {

            }

            @Override
            public void onResume(Animator newAnimator) {

            }
        });
    }

    /**
     * provider default is null
     *
     * @param provider provider
     */
    public void setAnimatorProvider(AnimatorProvider provider) {
        this.mProvider = provider;
        reset(mEmptyView);
        reset(mLoadingView);
        reset(mRetryView);
    }

    /**
     * reset view's property
     * 不然多次 setAnimatorProvider 后视图动画会混乱
     *
     * @param view view
     */
    private void reset(Component view) {
        if (view != null) {
            view.setTranslationX(0f);
            view.setTranslationY(0f);
            view.setAlpha(1f);
            view.setRotation(0f);
            view.setScaleX(1f);
            view.setScaleY(1f);
        }
    }

    private Component inflate(@LayoutRes int layoutResource, @ViewType int viewType) {
        final ComponentParent viewParent = getComponentParent();
        if (viewParent instanceof ComponentContainer) {
            if (layoutResource != 0) {
                final ComponentContainer parent = (ComponentContainer) viewParent;
                final LayoutScatter factory;
                if (mInflater != null) {
                    factory = mInflater;
                } else {
                    factory = LayoutScatter.getInstance(getContext());
                }
                final Component view = factory.parse(layoutResource, parent, false);
                final int index = parent.getChildIndex(this);

                // 防止还能触摸底下的 View
                view.setClickable(true);

                // 先不显示
                view.setVisibility(HIDE);
                ComponentContainer.LayoutConfig layoutParams;
                if (parent instanceof ListContainer) {
                    layoutParams = getLayoutConfig();
                } else {
                    layoutParams = view.getLayoutConfig();
                }
                if (layoutParams != null) {
                    judgeParentType(parent, layoutParams, view, index);
                } else {
                    parent.addComponent(view, index);
                }
                if (mLoadingView != null && mRetryView != null && mEmptyView != null) {
                    parent.removeComponent(this);
                }
                if (mInflateListener != null) {
                    mInflateListener.onInflate(viewType, view);
                }
                return view;
            } else {
                throw new IllegalArgumentException("StateView must have valid layoutResource");
            }
        } else {
            throw new IllegalStateException("StateView must have non-null ViewGroup viewParent");
        }
    }

    private void judgeParentType(ComponentContainer parent, LayoutConfig layoutParams, Component view, int index) {
        if (parent instanceof DependentLayout) {
            ComponentContainer.LayoutConfig lp = layoutParams;
            mLayoutParamsRelative.setMargins(lp.getMarginLeft(), lp.getMarginTop(),
                    lp.getMarginRight(), lp.getMarginBottom());
            parent.addComponent(view, index, mLayoutParamsRelative);
        } else if (parent instanceof DirectionalLayout) {
            parent.addComponent(view, index, mLayoutParamsConstrain);
        } else {
            if (isWrap) {
                inflateWrap(layoutParams);
            }
            parent.addComponent(view, index, layoutParams);
        }
    }

    private void inflateWrap(ComponentContainer.LayoutConfig layoutParams) {
        final int layoutWidth = 500;
        final int layoutHeight = 500;
        final int dividerNum = 2;
        layoutParams.height = layoutHeight;
        layoutParams.width = layoutWidth;
        int width = DisplayManager.getInstance().getDefaultDisplay(getContext()).
                get().getRealAttributes().width;
        int height = DisplayManager.getInstance().getDefaultDisplay(getContext()).
                get().getRealAttributes().height;
        layoutParams.setMarginLeft(width / dividerNum - layoutParams.width / dividerNum);
        layoutParams.setMarginTop(height / dividerNum - layoutParams.height / dividerNum);
    }

    /**
     * 设置 topMargin, 当有 actionbar/toolbar 的时候
     */
    public void setTopMargin() {
        ComponentContainer.LayoutConfig layoutParams = (ComponentContainer.LayoutConfig) getLayoutConfig();
        layoutParams.setMarginTop(getActionBarHeight());
    }

    /**
     * 获取动作栏高度
     *
     * @return int 动作栏高度
     */
    public int getActionBarHeight() {
        int height = 0;
        return height;
    }

    /**
     * 设置 emptyView 的自定义 Layout
     *
     * @param emptyResource emptyView 的 layoutResource
     */
    public void setEmptyResource(@LayoutRes int emptyResource) {
        this.mEmptyResource = emptyResource;
    }

    /**
     * 设置 retryView 的自定义 Layout
     *
     * @param retryResource retryView 的 layoutResource
     */
    public void setRetryResource(@LayoutRes int retryResource) {
        this.mRetryResource = retryResource;
    }

    /**
     * 设置 loadingView 的自定义 Layout
     *
     * @param loadingResource loadingView 的 layoutResource
     */
    public void setLoadingResource(@LayoutRes int loadingResource) {
        mLoadingResource = loadingResource;
    }

    /**
     * 获取LayoutScatter对象
     *
     * @return LayoutScatter LayoutScatter对象
     */
    public LayoutScatter getInflater() {
        return mInflater;
    }

    /**
     * 设置Inflater
     *
     * @param inflater inflater对象
     */
    public void setInflater(LayoutScatter inflater) {
        this.mInflater = inflater;
    }

    /**
     * 监听重试
     *
     * @param listener {@link OnRetryClickListener}
     */
    public void setOnRetryClickListener(OnRetryClickListener listener) {
        this.mRetryClickListener = listener;
    }

    /**
     * OnRetryClickListener
     *
     * @since 2021-04-26
     */
    public interface OnRetryClickListener {
        /**
         * 重试时单击
         */
        void onRetryClick();
    }

    /**
     * Specifies the inflate listener to be notified after this StateView successfully
     * inflated its layout resource.
     *
     * @param inflateListener The OnInflateListener to notify of successful inflation.
     * @see OnInflateListener
     */
    public void setOnInflateListener(OnInflateListener inflateListener) {
        mInflateListener = inflateListener;
    }

    /**
     * OnInflateListener
     *
     * @since 2021-04-26
     */
    public interface OnInflateListener {
        /**
         * 组件Inflate
         *
         * @param viewType 组件类型
         * @param view     组件
         */
        void onInflate(@ViewType int viewType, Component view);
    }
}
